import { Component, OnInit } from '@angular/core';

import { Observable, Subject } from 'rxjs';

import {
  debounceTime, distinctUntilChanged, switchMap
} from 'rxjs/operators';

import  {Hero} from "../Hero";
import { HeroService } from '../hero.service';

@Component({
  selector: 'app-hero-search',
  templateUrl: './hero-search.component.html',
  styleUrls: [ './hero-search.component.css' ]
})
export class HeroSearchComponent implements OnInit {


// Push a search term into the observable stream.

  //  <!--    $ 是一个约定，表示 heroes$ 是一个 Observable 而不是数组-->
  heroes$!: Observable<Hero[]>;

  /**
   *  RxJS 中 Subject 是一种特殊类型的 Observable，它允许将值多播给多个观察者，
   *  所以 Subject 是多播的，而普通的 Observables 是单播的(每个已订阅的观察者都拥有 Observable 的独立执行)。
   *
   *  在 RxJS 中常用有四种 Subject 分别是：普通Subject，BehaviorSubject，AsyncSubject，ReplaySubject。
   *
   *  Subject 既是可观察对象的数据源，本身也是 Observable。你可以像订阅任何 Observable 一样订阅 Subject。
   * @private
   */

  // searchTerms 属性是 RxJS 的 Subject 类型。
  private searchTerms = new Subject<string>();

  constructor(private heroService: HeroService) {}

  // Push a search term into the observable stream.
  /**
   * 调用它的 next(value) 方法往 Observable 中推送一些值，就像 search() 方法中一样。
   *
   * 文本框的 input 事件的事件绑定会调用 search() 方法。
   * @param term
   */
  search(term: string): void {
    this.searchTerms.next(term);
  }

  /**
   * 在传出最终字符串之前，debounceTime(300) 将会等待，直到新增字符串的事件暂停了 300 毫秒
   * 实际发起请求的间隔永远不会小于 300ms。
   *
   * distinctUntilChanged() 会确保只在过滤条件变化时才发送请求
   *
   * switchMap() 会为每个从 debounce() 和 distinctUntilChanged() 中通过的搜索词调用搜索服务
   * 它会取消并丢弃以前的搜索可观察对象，只保留最近的。
   */
  ngOnInit(): void {
    this.heroes$ = this.searchTerms.pipe(
      // 每次按键后等待300ms，然后再考虑该术语
      debounceTime(300),

      //如果与上一术语相同，则忽略新术语
      distinctUntilChanged(),

      // 每次术语更改时，切换到新的可观察搜索
      switchMap((term: string) => this.heroService.searchHeroes(term)),
    );
  }
}
